'''
This file is part of ModeliMark.

ModeliMark is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.

ModeliMark is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with ModeliMark.
If not, see <http://www.gnu.org/licenses/>.

Copyright 2011 Jens Frenkel
'''

import wrapper
import numbers
import shlex, subprocess
import os
from time import *



#compiler_mode = "FMU"
compiler_mode = "FMU"


class JModelica(wrapper.BaseWrapper):
    '''
    classdocs
    '''


    def __init__(self):
        '''
        Constructor
        '''
        # Import the function for compilation of models and the FMUModel class
 
    def flatten(self, model, files):
        '''
        instructs the compiler to parse the Modelica
        code and return the flat model
        
        :param model: Name of the Model to flatten.
        :type model: String.
             
        :param files: all Files of the Model to flatten.
        :type files: list of String.
        '''       
        assert(isinstance(model,str))
        assert(isinstance(files,list))

        from jmodelica.fmi import compile_fmu
        from jmodelica.fmi import FMUModel
        from jmodelica.compiler import CompilerError
        from jmodelica.compiler import ModelicaCompiler
        
        t1 = clock()

        mc = ModelicaCompiler()
        t2 = clock()
        sr = mc.parse_model(files)
        t3 = clock()
        ir = mc.instantiate_model(sr,model)
        t4 = clock()
        fc = mc.flatten_model(ir)
        t5 = clock()
#        mc.generate_code(fc)
#        t6 = clock()

        #print "parse: " + str(t3-t2)
        #print "instantiate: " + str(t4-t3)
        #print "flatten: " + str(t5-t4)
        #print "code gen: " + str(t6-t5)

        dt = t5-t2
        
        return None,dt

    def translate(self, model, files):
        '''
        flattens the model and turns it into a state which can be simulated
        
        :param model: Name of the Model to flatten.
        :type model: String.   
             
        :param files: all Files of the Model to flatten.
        :type files: list of String. 
        '''         
        assert(isinstance(model,str))
        assert(isinstance(files,list))       
    
    
        from jmodelica.fmi import compile_fmu
        from jmodelica.fmi import FMUModel
        from jmodelica.compiler import CompilerError
        from jmodelica.compiler import ModelicaCompiler
            
        pfiles = list()
        for a in files:
            pfiles.append(a)
            #pfiles.append('%s/%s'%(os.getcwd(),a))        
        
        # Compile model
        if compiler_mode=="FMU":
            t1 = clock()
            fmu_name = compile_fmu(model,pfiles)
        else:
            t1 = clock()
            jmu_name = compile_jmu(model,pfiles)
    
        t2 = clock()
        dt = t2 - t1
            
        return None,dt                
    
    def simulate(self, model, files, startTime, outputInterval, stopTime):
        '''
        flattens, translates and simulates the model using the standard solver
        and a predefined output interval and stop time
        
        :param model: Name of the Model to flatten.
        :type model: String.   
             
        :param files: all Files of the Model to flatten.
        :type files: list of String. 
        
        :param startTime: Start Time of the Simulation
        :type startTime: numbers.Real.
                
        :param outputInterval: Intervall for Output of Results.
        :type outputInterval: numbers.Real. 
        
        :param stopTime: Stop Time of the Simulation
        :type stopTime: numbers.Real. 
        '''         
        assert(isinstance(model,str))
        assert(isinstance(files,list))
        assert(isinstance(startTime,numbers.Real))
        assert(isinstance(outputInterval,numbers.Real))
        assert(isinstance(stopTime,numbers.Real))        
        
        from jmodelica.fmi import compile_fmu
        from jmodelica.fmi import FMUModel
        from jmodelica.compiler import CompilerError
        from jmodelica.compiler import ModelicaCompiler        
        
        pfiles = list()
        for a in files:
            pfiles.append(a)
            #pfiles.append('%s/%s'%(os.getcwd(),a))        
        
        try:
            # Compile model
            if compiler_mode=="FMU":
                t1 = clock()
                fmu_name = compile_fmu(model,pfiles)
            else:
                t1 = clock()
                jmu_name = compile_jmu(model,pfiles)
    
   
            # Load model
            if compiler_mode=="FMU":
                model = FMUModel(fmu_name)
            else:
                model = JMUModel(jmu_name)
                
            res = model.simulate(start_time=startTime,final_time=stopTime)
            t2 = clock()
            
            dt = t2 - t1 
               
            return res, dt   
        except (CompilerError):
            pass 
        
        return False          
    
